# -*- coding:utf-8 -*-

import os
import sys
import time
import shutil
import threading
import unittest

from FileCount import FileCount
from MyLogger import MyLogger, TIMEROTATE, SIZEROTATE
from MyException import NoKeyError

class Send(threading.Thread):
    def __init__(self, profile, ftp_client_list, path_client_list, send_file_list, statinfo_map):
        """
        初始化
        """
        #初始化线程类
        threading.Thread.__init__(self)
        #初始化私有配置
        self.profile = profile
        #初始化文件引用计数
        self.file_count_list = FileCount()
        #初始化匹配结果列表
        self.send_file_list = send_file_list
        #初始化统计日志信息
        self.statinfo_map = statinfo_map
        #初始化FTP模块列表
        self.ftp_client_list = ftp_client_list
        #初始化PAT模块列表
        self.path_client_list = path_client_list
        #初始化日志
        self.success_logger = MyLogger(os.path.join(profile.log_dir, "Send_success.log"), SIZEROTATE, profile.size_rotate_backup_num)
        self.error_logger = MyLogger(os.path.join(profile.log_dir, "Send_error.log"), SIZEROTATE, profile.size_rotate_backup_num)
        
        #超时文件删除日志
        self.overtime_logger = MyLogger(os.path.join(profile.log_dir, "overtime.log"), SIZEROTATE, profile.size_rotate_backup_num)
    
    def update_file_count(self):
        """
        从发送接口模块已处理文件列表中获取已处理文件列表，更新文件引用计数
        """
        #更新FTP模块文件计数
        for ftp_client in self.ftp_client_list:    
            #获取FTP模块已处理文件
            file_list = ftp_client.send_file_list.get_all()
            #更新文件引用计数
            for filename in file_list:
                self.file_count_list.file_dec(filename)
                
        #更新PATH模块文件计数
        for path_client in self.path_client_list:
            #获取PATH模块处理文件
            file_list = path_client.send_file_list.get_all()
            #更新文件引用计数
            for filename in file_list:
                self.file_count_list.file_dec(filename)
    
    def del_receiveorsendlst_overtime_file(self,filename):
        """
        从发送接口模块接收的文件列表和已经发送文件列表里面删除掉超时的文件，实际情况可能超时的文件判断后，等待删除时候已经发送了
        add by wshi 2012-09-22
        """
        #更新FTP模块
        for ftp_client in self.ftp_client_list:    
            ftp_client.receive_file_list.del_item(filename)
            ftp_client.send_file_list.del_item(filename)

        #更新PATH模块
        for path_client in self.path_client_list:
            path_client.receive_file_list.del_item(filename)
            path_client.send_file_list.del_item(filename)
               
    def display(self):
        '''
        打印列表里面的保存的文件名信息
        add by wshi 2012-09-22
        '''
        if len(self.file_count_list.file_count_map) <1 and len(self.file_count_list.file_time_map) < 1:
            return
        self.overtime_logger.info("filecountmap size:%d,filetimemap size:%d" %(len(self.file_count_list.file_count_map),len(self.file_count_list.file_time_map)))
        #self.success_logger.info("display***********************start")
#        for file in self.file_count_list.file_count_map:
#            self.success_logger.info("file:%s,count:%d" %(file,self.file_count_list.file_count_map[file]))
#        
#        for name in self.file_count_list.file_time_map:
#            self.success_logger.info("file:%s,time:%d" %(name,self.file_count_list.file_time_map[name]))
                        
        #self.success_logger.info("display***********************end")
        
    def delete_free_file(self):
        """
        从文件引用计数列表中获取无引用文件，并删除
        """
        #获取无引用文件
        free_file_list = self.file_count_list.get_free_file()
        
        #删除无引用文件及统计日志信息
        for filename in free_file_list:
            try:
                self.statinfo_map.delete(filename)
                self.success_logger.info("Success delete statinfo for file: %s"%(filename))
            except:
                self.error_logger.exception("Error delete statinfo for file: %s"%(filename))
            try:
                file_path = os.path.join(self.profile.send_dir, filename)
                os.remove(file_path)
                self.success_logger.info("Success delete file: %s"%(filename))
            except:
                self.error_logger.exception("Error delete file: %s"%(filename))
           
                
    def delete_overwait_file(self):
        """
        删除发送目录下面长时间没有发送的文件
        add by wshi 2012-09-22
        """
        #获取发送目录下面的文件
        overwait_file_list = os.listdir(self.profile.send_dir)
        
        for filename in overwait_file_list:
            try:
                #判断文件名最后修改时间是否超过最大等待时间
                strPath = os.path.join(self.profile.send_dir,filename)
                lastTime = os.path.getmtime(strPath)
                if (time.time()-lastTime) < self.profile.send_overflow_time:
                    continue
                
                #文件没有超时，不处理
                if not self.file_count_list.is_overtime_file(filename,self.profile.send_overtime):
                    continue
            except Exception, msg:
                self.overtime_logger.exception("[overwait]\tJudge the file %s overtime error:%s"%(filename,str(msg)))
                continue
                
            try:
                #删除正在处理队列里面的该文件引用
                self.del_receiveorsendlst_overtime_file(filename)
                #self.overtime_logger.info("[overwait]\tSuccess delete receive_file_list for file: %s"%(filename))
            except Exception, msg:
                self.overtime_logger.exception("[overwait]\tdelete file in receive_file_list or send_file_list for file: %s  error:%s"%(filename,str(msg)))
            
            try:
                #将文件引用计数设置为0
                self.file_count_list.set_file(filename, 0)
                self.overtime_logger.info("[overwait]\tSuccess set the file %s refrence 0"%(filename))
            except Exception, msg:
                self.overtime_logger.exception("[overwait]\tdelete file in receive_file_list for file: %s error:%s"%(filename,str(msg)))
            
                
                 
    def dispatch_file(self):
        """
        将匹配结果中文件分发到FTP接口或PATH接口中
        """
        #获取匹配规则
        match_result_list = self.send_file_list.get_all()
                
        #分发文件到FTP模块列表
        for match_result in match_result_list:
            #初始化文件引用计数
            ref_count = 0
            try:
                #分发文件到FTP接口
                for ftp in match_result.ftp_list:
                    if ftp[1]:
                        ftp[1].receive_file_list.add(match_result.filename)
                        ref_count += 1
                        self.success_logger.info("Success dispatch file: %s to ftp: %s"%(match_result.filename, ftp[0]))
                    else:
                        self.error_logger.info("Error dispatch file: %s to ftp: %s"%(match_result.filename, ftp[0]))
                    
                #分发文件到PATH接口
                for path in match_result.path_list:
                    if path[1]:
                        path[1].receive_file_list.add(match_result.filename)
                        ref_count += 1
                        self.success_logger.info("Success dispatch file: %s to path: %s"%(match_result.filename, path[0]))
                    else:
                        self.error_logger.info("Error dispatch file: %s to path: %s"%(match_result.filename, path[0]))
            except Exception, msg:
                self.error_logger.info("add the file %s to receive list error:%s" %(match_result.filename,str(msg)))
                ref_count = 0
            #创建文件引用计数
            self.file_count_list.add_file(match_result.filename, ref_count)

    def run(self):
        while(True):
            try:
                #分发文件到FTP接口和PATH接口
                self.dispatch_file()
                
                #更新引用计数列表
                self.update_file_count()
                        
                #删除无引用计数
                self.delete_free_file()
                
                #删除在发送目录下面长时间没有发送的文件
                self.delete_overwait_file()
                
                #打印文件引用列表数目
                self.display()
            except Exception, msg:
                self.error_logger.exception(msg)
            except:
                self.error_logger.exception("Unknown error")
                raise
            
            time.sleep(1)
                
class SendTestCase(unittest.TestCase):
    def setUp(self):
        self.profile = Profile()
        if not os.path.exists(self.profile.work_dir):
            os.makedirs(self.profile.work_dir)
        if not os.path.exists(self.profile.send_dir):
            os.makedirs(self.profile.send_dir)
        if not os.path.exists(self.profile.send_backup_dir):
            os.makedirs(self.profile.send_backup_dir)
        
        self.ftpinfo_1 = FTPInfo()
        self.ftpinfo_1.name = "APP_FTP_TEST"
        self.ftpinfo_1.ip_list.append("192.168.0.100")   
        
        self.ftpinfo_2 = FTPInfo()
        self.ftpinfo_2.name = "CB_FTP_TEST"
        self.ftpinfo_2.ip_list.append("192.168.0.110") 
        
        self.ftpclient_1 = FTPClient(self.profile, self.ftpinfo_1)  
        self.ftpclient_2 = FTPClient(self.profile, self.ftpinfo_2)   
        
        self.ftp_send_list = ListMutex()
        self.ftp_client_list = []
        
    def tearDown(self):
        pass
    
    def testOneFTP(self):
        print "--------1 test one ftp--------"
        self.PrepareData(False)

        self.ftpclient_1.setDaemon(True)
        self.ftpclient_1.start()
        
        self.ftp_client_list.append(self.ftpclient_1)
        
        self.send = Send(self.profile, self.ftp_client_list, self.ftp_send_list)
        self.send.setDaemon(True)
        self.send.start()
        time.sleep(15)
        
    def testTwoFTP(self):
        print "--------2 test two ftp--------"
        self.PrepareData(True)
        
        self.ftpclient_1.setDaemon(True)
        self.ftpclient_1.start()

        self.ftpclient_2.setDaemon(True)
        self.ftpclient_2.start()
        
        self.ftp_client_list.append(self.ftpclient_1)
        self.ftp_client_list.append(self.ftpclient_2)
        
        self.send = Send(self.profile, self.ftp_client_list, self.ftp_send_list)
        self.send.setDaemon(True)
        self.send.start()
        time.sleep(15)
    
    def PrepareData(self, flag):
        data_dir = "../data"
        file_list = os.listdir(data_dir)
        for filename in file_list: 
            src_file = os.path.join(data_dir, filename)
            dst_file = os.path.join(self.profile.send_dir, filename)
            shutil.copyfile(src_file, dst_file)
            match_result = MatchResult(filename)
            match_result.ftp_list.append(("APP_FTP_TEST", self.ftpclient_1))
            if flag:
                match_result.ftp_list.append(("CB_FTP_TEST", self.ftpclient_2))                
            self.ftp_send_list.add(match_result)        
    
if __name__ == "__main__":
    flag = sys.argv[1]
    suite = unittest.TestSuite()
    if flag == "1":
        suite.addTest(SendTestCase("testOneFTP"))
    elif flag == "2":
        suite.addTest(SendTestCase("testTwoFTP"))
    
    runner = unittest.TextTestRunner()
    runner.run(suite)
        
        
    